import { Asset, assetManager, AssetManager, NodePool, resources   } from "cc";
import { BaseModule } from "./base/BaseModule";

export class ResourceSystem extends BaseModule
{
    private _cache: Map<string, Asset> = new Map();
    private _refCount: Map<string, number> = new Map();
    private _remoteUrl: string = "";
    private _pools: Map<string, NodePool> = new Map();
    private _bundles: Map<string, AssetManager.Bundle> = new Map();

    init() {
        // 初始化资源系统
        console.log("ResourceSystem initialized");
    }

    shutdown(): void {
        this.clearAll();
        console.log("ResourceSystem shutdown");
    }

    /**
     * 设置远程资源服务器地址
     * @param url 远程服务器地址
     */
    setRemoteUrl(url: string) {
        this._remoteUrl = url;
    }

    /**
     * 加载资源包
     * @param bundleName 资源包名称
     * @returns Promise<Bundle>
     */
    async loadBundle(bundleName: string): Promise<AssetManager.Bundle> {
        // 如果已经加载过该资源包，直接返回
        if (this._bundles.has(bundleName)) {
            return this._bundles.get(bundleName)!;
        }

        return new Promise<AssetManager.Bundle>((resolve, reject) => {
            // 从assetManager加载资源包
            assetManager.loadBundle(bundleName, (err, bundle) => {
                if (err) {
                    console.error(`加载资源包失败: ${bundleName}`, err);
                    reject(err);
                    return;
                }
                
                this._bundles.set(bundleName, bundle);
                console.log(`资源包加载成功: ${bundleName}`);
                resolve(bundle);
            });
        });
    }

    /**
     * 从指定资源包加载资源
     * @param bundleName 资源包名称
     * @param path 资源路径
     * @param type 资源类型
     * @returns Promise<T>
     */
    async loadFromBundle<T extends Asset>(bundleName: string, path: string, type: new () => T): Promise<T> {
        // 确保资源包已加载
        let bundle: AssetManager.Bundle;
        if (this._bundles.has(bundleName)) {
            bundle = this._bundles.get(bundleName)!;
        } else {
            bundle = await this.loadBundle(bundleName);
        }

        // 构建带资源包名称的缓存键
        const cacheKey = `${bundleName}@${path}`;

        // 先尝试从缓存加载
        if (this._cache.has(cacheKey)) {
            this._refCount.set(cacheKey, (this._refCount.get(cacheKey) || 0) + 1);
            return this._cache.get(cacheKey) as T;
        }

        // 从指定资源包加载资源
        return new Promise<T>((resolve, reject) => {
            bundle.load(path, type, (err, asset) => {
                if (err) {
                    console.error(`从资源包加载资源失败: ${bundleName}/${path}`, err);
                    reject(err);
                    return;
                }
                
                this._cache.set(cacheKey, asset);
                this._refCount.set(cacheKey, 1);
                resolve(asset as T);
            });
        });
    }

    /**
     * 从指定资源包预加载资源
     * @param bundleName 资源包名称
     * @param paths 资源路径数组
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    preloadFromBundle(bundleName: string, paths: string[], type: typeof Asset, onProgress?: (finish: number, total: number) => void): Promise<void> {
        return new Promise(async (resolve, reject) => {
            // 确保资源包已加载
            let bundle: AssetManager.Bundle;
            if (this._bundles.has(bundleName)) {
                bundle = this._bundles.get(bundleName)!;
            } else {
                bundle = await this.loadBundle(bundleName);
            }

            bundle.preload(paths, type, (finish, total, item) => {
                onProgress && onProgress(finish, total);
            }, (error) => {
                if (error) {
                    reject(error);
                } else {
                    resolve();
                }
            });
        });
    }

    /**
     * 释放资源包
     * @param bundleName 资源包名称
     */
    releaseBundle(bundleName: string) {
        if (this._bundles.has(bundleName)) {
            const bundle = this._bundles.get(bundleName)!;
            
            // 释放资源包中的所有资源
            bundle.releaseAll();
            
            // 从管理器中移除
            this._bundles.delete(bundleName);
            
            console.log(`资源包已释放: ${bundleName}`);
        }
    }

    /**
     * 获取资源包
     * @param bundleName 资源包名称
     * @returns Bundle | undefined
     */
    getBundle(bundleName: string): AssetManager.Bundle | undefined {
        return this._bundles.get(bundleName);
    }

    /**
     * 加载资源（兼容原有resources加载方式）
     * @param path 资源路径
     * @param type 资源类型
     * @returns Promise<T>
     */
    async load<T extends Asset>(path: string, type: new () => T): Promise<T> {
        // 先尝试从缓存加载
        if (this._cache.has(path)) {
            this._refCount.set(path, (this._refCount.get(path) || 0) + 1);
            return this._cache.get(path) as T;
        }

        // 从resources加载资源
        return new Promise<T>((resolve, reject) => {
            resources.load(path, type, (err, asset) => {
                if (err) {
                    console.error(`加载资源失败: ${path}`, err);
                    reject(err);
                    return;
                }
                
                this._cache.set(path, asset);
                this._refCount.set(path, 1);
                resolve(asset as T);
            });
        });
    }

    /**
     * 释放资源
     * @param path 资源路径
     */
    release(path: string) {
        const count = (this._refCount.get(path) || 0) - 1;
        if (count <= 0) {
            resources.release(path);
            this._cache.delete(path);
            this._refCount.delete(path);
        } else {
            this._refCount.set(path, count);
        }
    }

    /**
     * 获取对象池
     * @param prefabName 预制体名称
     * @returns NodePool
     */
    getPool(prefabName: string): NodePool {
        if (!this._pools.has(prefabName)) {
            this._pools.set(prefabName, new NodePool(prefabName));
        }
        return this._pools.get(prefabName)!;
    }

    /**
     * 预加载资源（兼容原有resources预加载方式）
     * @param paths 资源路径数组
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    preload(paths: string[], type: typeof Asset, onProgress?: (finish: number, total: number) => void): Promise<void> {
        return new Promise((resolve, reject) => {
            resources.preload(paths, type, (finish, total, item) => {
                onProgress && onProgress(finish, total);
            }, (error) => {
                if (error) {
                    reject(error);
                } else {
                    resolve();
                }
            });
        });
    }

    /**
     * 清理所有资源缓存
     */
    clearAll() {
        this._cache.clear();
        this._refCount.clear();
        
        // 清理对象池
        for (const pool of this._pools.values()) {
            pool.clear();
        }
        this._pools.clear();
        
        // 清理资源包
        for (const [name, bundle] of this._bundles) {
            bundle.releaseAll();
        }
        this._bundles.clear();
    }
}